using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using AForge.Imaging.Filters;
using System.Drawing.Imaging;

namespace PBR.Filters
{
    /// <summary>
    /// Composites one stroke onto the image
    /// </summary>
    public class StrokeComposite
    {
        /// <summary>
        /// Composites the overImage onto the underImage
        /// </summary>
        /// <param name="underImage"></param>
        /// <param name="overImage"></param>
        /// <param name="rect"></param>
        /// <returns></returns>
        public void ApplyInPlace(Bitmap underImage, Bitmap overImage, Rectangle compositeRect,
            Rectangle sourceRect, Stroke[,] strokeArray, Stroke stroke)
        {
            if (underImage.PixelFormat != PixelFormat.Format32bppArgb || overImage.PixelFormat != PixelFormat.Format32bppArgb)
            {
                throw new ArgumentException("Stroke composite needs 2 32bppArgb images");
            }
            if (overImage.Size != compositeRect.Size)
            {
                throw new ArgumentException("Stroke scaling not supported");
            }
            BitmapData underImageData = underImage.LockBits(
                new Rectangle(0, 0, underImage.Width, underImage.Height),
                ImageLockMode.ReadWrite, underImage.PixelFormat);

            BitmapData overImageData = overImage.LockBits(
                new Rectangle(0, 0, overImage.Width, overImage.Height),
                ImageLockMode.ReadOnly, overImage.PixelFormat);

            ProcessFilter(underImageData, overImageData, compositeRect, sourceRect, strokeArray, stroke);

            // unlock destination images
            underImage.UnlockBits(underImageData);
            overImage.UnlockBits(overImageData);
        }

        private unsafe void ProcessFilter(BitmapData underData, BitmapData overData, Rectangle compositeRect,
            Rectangle sourceRect, Stroke[,] strokeArray, Stroke stroke)
        {
            Rectangle paintRect = new Rectangle(compositeRect.X - sourceRect.X, compositeRect.Y - sourceRect.Y,
                compositeRect.Width, compositeRect.Height);

			// get width and height
            int width = overData.Width;
            int height = overData.Height;

            int underOffset = underData.Stride - underData.Width * 4;
            int overOffset = overData.Stride - overData.Width * 4;

			// do the job
			byte* underPtr = (byte *) underData.Scan0.ToPointer();
            byte* overPtr = (byte *) overData.Scan0.ToPointer();

			// for each line
            for (int overY = paintRect.Top; overY < paintRect.Bottom; overY++)
			{
                underPtr = (byte*)underData.Scan0.ToPointer() + underData.Stride * (overY) + paintRect.Left * 4;
                // for each pixel
                for (int overX = paintRect.Left; overX < paintRect.Right; overX++, underPtr += 4, overPtr += 4)
				{
                    if (sourceRect.Contains(overX + sourceRect.X, overY + sourceRect.Y))
                    {
                        underPtr[AForge.Imaging.RGBA.R] = (byte)((underPtr[AForge.Imaging.RGBA.R] * (255 - overPtr[AForge.Imaging.RGBA.A]) +
                            overPtr[AForge.Imaging.RGBA.R] * overPtr[AForge.Imaging.RGBA.A]) / 255);
                        underPtr[AForge.Imaging.RGBA.G] = (byte)((underPtr[AForge.Imaging.RGBA.G] * (255 - overPtr[AForge.Imaging.RGBA.A]) +
                            overPtr[AForge.Imaging.RGBA.G] * overPtr[AForge.Imaging.RGBA.A]) / 255);
                        underPtr[AForge.Imaging.RGBA.B] = (byte)((underPtr[AForge.Imaging.RGBA.B] * (255 - overPtr[AForge.Imaging.RGBA.A]) +
                            overPtr[AForge.Imaging.RGBA.B] * overPtr[AForge.Imaging.RGBA.A]) / 255);
                        underPtr[AForge.Imaging.RGBA.A] = (byte)255;/*(byte)((underPtr[AForge.Imaging.RGBA.A] * (255 - overPtr[AForge.Imaging.RGBA.A]) +
                            overPtr[AForge.Imaging.RGBA.A] * overPtr[AForge.Imaging.RGBA.A]) / 255);*/
                        if (overPtr[AForge.Imaging.RGBA.A] > 100)
                        {
                            strokeArray[overX + sourceRect.X, overY + sourceRect.Y] = stroke;
                        }
				    }
                }
                overPtr += overOffset;
			}
		}
    }
}

